#!/bin/bash -f

#     Copyright 2011 Nicolas Melot
# 
#    Nicolas Melot (nicolas.melot@liu.se)
# 
# 
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
# 
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
# 
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

. ./settings
. ./variables

log_start()
{
	echo -n "$@"
	echo -n "$@" >> $logfile

}

log_stop()
{
	echo "$@"
	echo "$@" >> $logfile
}

log()
{
	log_start "$@"
	log_stop ""
}

run()
{
	$@
}

info_start()
{
	log_start '[INFO] '"$@"
}

info_stop()
{
	log_stop "$@"
}

info()
{
	info_start "$@"
	info_stop ""
}

error()
{
	log '[ERROR] '"$@"
}

usage()
{
	echo ./start \[compile\|run\] \<experiment\>
}

cut_head()
{
	echo \(`echo $@|cut -f 1 -d ' ' --complement`\)
}

get_date()
{
	echo `date +%D\ %R:%S`
}

build_args()
{
	# $1 is the variable containing the list of variables to be listed
	eval myvars=\(`echo $@`\)
	eval next_step=`cut_head ${myvars[@]}`
	var=${myvars[0]}

	for val in `eval echo \$\{$var\[\@\]\}`
	do
		if [ "x$#" != "x1" ];
		then
			build_args ${next_step[@]}|while read line
			do
				echo $val $line
			done
		else
			echo $val
		fi
	done
}

count_args()
{
	count=1
	eval myvars=\(`echo $@`\)

	for var in ${myvars[@]};
	do
		count=$(($count * $(echo $(eval echo \$\{$var\[\@\]\})|wc -w)))
	done
	echo $count
}

merge_data()
{
	info Merging all results of the same experiment together

	echo -e $HEADER > $data$ext
	echo %\ ${compile[@]}\ ${run[@]}\ $output >> $data$ext
	cat data-$experiment-*.m|grep -v %|grep -v function|grep -v end|grep -v \\\]\; |grep -v x\ =\ \\\[ >> $data$ext
	echo -e $FOOTNOTE >> $data$ext
}

compile()
{
	total_instances=`count_args ${compile[@]}`
	info Will compile $total_instances settings

	compile_counter=1
	total_time=0
	start_time=`date +%s`
	build_args ${compile[@]}|while read args; do
		info_start Setting $compile_counter/$total_instances: `for i in $(seq 0 $((${#compile[@]} - 1)));do echo "${compile[$i]}=$(echo $args|cut -d ' ' -f $(($i + 1)))"; done`"... "
		instance_start=`date +%s`
		bash ./compile $args 2>&1 > /dev/null
		instance_stop=`date +%s`
		compile_time=$(($instance_stop - $instance_start))
		total_time=$(($total_time + $compile_time))
		remaining=$((($total_instances - $compile_counter) * ($total_time / $compile_counter)))
		info_stop $compile_time sec finished on $(echo -n `get_date`)\; approx. $remaining sec left \($(($remaining / 60)) minutes, $(($remaining / 60 / 60)) hours, $(($remaining / 60 / 60 / 24)) days\)
		compile_counter=$(($compile_counter + 1))
	done
	stop_time=`date +%s`
	overall_time=$(($stop_time - start_time))
	info Compilation took $overall_time seconds \($(($overall_time / 60)) minutes or $(($overall_time / 60 / 60)) hours\) or $(($overall_time / $total_instances)) seconds per compilation setting \($(($overall_time / $total_instances / 60)) minutes or $(($overall_time / $total_instances / 60 / 60)) hours\).
}

batch()
{
	run_instances=`count_args ${run[@]}`
	compile_instances=`count_args ${compile[@]}`

	total_instances=$(($run_instances * $compile_instances))

	info Will run $total_instances instances

	# Initialize output file
	start_time=`date +%s`
	filename=$data-$experiment-`date|tr ' ' _|tr : -`$ext
	echo -e $HEADER > $filename
	echo %\ ${compile[@]}\ ${run[@]}\ $output >> $filename

	compile_counter=0
	build_args ${compile[@]}|while read flags; do
		run_counter=1	
		total_time=0
		build_args ${run[@]}|while read args; do
			already_run=$((compile_counter * $run_instances + $run_counter))
			info_start Instance $already_run/$total_instances: `for i in $(seq 0 $((${#compile[@]} - 1)));do echo "${compile[$i]}=$(echo $flags|cut -d ' ' -f $(($i + 1))) "; done``for i in $(seq 0 $((${#run[@]} - 1)));do echo "${run[$i]}=$(echo $args|cut -d ' ' -f $(($i + 1)))"; done`"... "
			instance_start=`date +%s`
			bash ./run $flags $args|while read line;
			do
				# Add content to output file
				echo $flags $args $line >> $filename
			done
			instance_stop=`date +%s`
			run_time=$(($instance_stop - $instance_start))
			total_time=$(($total_time + $run_time))
			remaining=$((($total_instances - $already_run) * ($total_time / $run_counter)))

			info_stop $run_time sec finished on $(echo -n `get_date`)\; approx. $remaining sec left \($(($remaining / 60)) minutes, $(($remaining / 60 / 60)) hours, $(($remaining / 60 / 60 / 24)) days\)

			run_counter=$(($run_counter + 1))
		done
		compile_counter=$(($compile_counter + 1))
	done

	# Finalize output file
	echo -e $FOOTNOTE >> $filename
	stop_time=`date +%s`
	overall_time=$(($stop_time - start_time))
	info Instances took $overall_time seconds \($(($overall_time / 60)) minutes or $(($overall_time / 60 / 60)) hours\) to run, or $(($overall_time / $total_instances)) seconds per instance run \($(($overall_time / $total_instances / 60)) minutes or $(($overall_time / $total_instances / 60 / 60)) hours\).
}

operation=$1
experiment=$2

echo -n "" > $logfile

case "x$operation" in
	"xcompile")
		compile

		exit 0
	;;
	"xrun")
		if [ "x$experiment" == "x" ];
		then
			error You must name the experiment to be run
			usage
			exit 1
		else
			batch
			merge_data

			exit 0
		fi
	;;
	"xmerge")
		if [ "x$experiment" == "x" ];
		then
			error You must name the experiment to be run
			usage
			exit 1
		else
			merge_data

			exit 0
		fi
	;;		
	*)
		error Unknown operation
		usage

		exit 1
	;;
esac
